// UserPreferences.cs
// Facebook/Framework/Service
// Copyright (c) 2007, Nikhil Kothari. All Rights Reserved.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using Facebook.Service.Core;

namespace Facebook.Service {

    /// <summary>
    /// Represents the set of preferences or profile object associated with the user.
    /// </summary>
    public class UserPreferences {

        private const int MinimumKey = 0;
        private const int MaximumKey = 200;

        private Dictionary<int, string> _data;

        private Dictionary<int, bool> _changedKeys;
        private bool _cleared;

        /// <summary>
        /// Initializes an instance of a UserPreferences object.
        /// </summary>
        public UserPreferences() {
            _data = new Dictionary<int, string>();
        }

        /// <summary>
        /// Indicates whether the preferences have changed since it was loaded.
        /// </summary>
        public bool IsDirty {
            get {
                return (_changedKeys != null) || _cleared;
            }
        }

        /// <summary>
        /// Gets or sets a particular preference item. Preference items are identified
        /// by a numeric key.
        /// </summary>
        /// <param name="index">The key identifying the particular item.</param>
        /// <returns>The value of the item, or null if it doesn't exist.</returns>
        public string this[int index] {
            get {
                if ((index < MinimumKey) || (index > MaximumKey)) {
                    throw new ArgumentOutOfRangeException("index");
                }

                if (_data.ContainsKey(index)) {
                    return _data[index];
                }

                return null;
            }
            set {
                if ((index < MinimumKey) || (index > MaximumKey)) {
                    throw new ArgumentOutOfRangeException("index");
                }

                if (value == null) {
                    value = String.Empty;
                }

                _data[index] = value;
                if (_cleared == false) {
                    if (_changedKeys == null) {
                        _changedKeys = new Dictionary<int, bool>();
                    }
                    _changedKeys[index] = true;
                }
            }
        }

        /// <summary>
        /// Clears all the items from the preferences.
        /// </summary>
        public void Clear() {
            _cleared = true;
            _data.Clear();
            _changedKeys = null;
        }

        /// <summary>
        /// Gets the value of the particular preference item. If the value is not set,
        /// the default value is returned.
        /// </summary>
        /// <param name="index">The key identifying the particular item.</param>
        /// <param name="defaultValue">The default value to use as a fallback.</param>
        /// <returns>The value of the item.</returns>
        public string GetValue(int index, string defaultValue) {
            string value = this[index];
            if (value == null) {
                return defaultValue;
            }
            return value;
        }

        internal void Load(ArrayList items) {
            foreach (JsonObject obj in items) {
                int index = (int)obj["pref_id"];
                string value = (string)obj["value"];

                _data[index] = value;
            }

            OnLoaded();
        }

        /// <summary>
        /// Allows a derived UserPreferences object to perform logic after it has
        /// been loaded from the current state managed by the Facebook service.
        /// </summary>
        protected virtual void OnLoaded() {
        }

        /// <summary>
        /// Allows a derived UserPreferences object to perform logic before it
        /// is saved to the Facebook service.
        /// </summary>
        protected virtual void OnSaving() {
        }

        /// <summary>
        /// Removes the specified item from the preferences.
        /// </summary>
        /// <param name="index">The key identifying the particular item.</param>
        public void RemoveValue(int index) {
            this[index] = null;
        }

        internal string Save(bool replacing) {
            OnSaving();

            StringBuilder sb = new StringBuilder(1024);
            bool firstItem = true;

            sb.Append("{");

            if (_cleared || replacing) {
                foreach (KeyValuePair<int, string> keyValue in _data) {
                    if (firstItem == false) {
                        sb.Append(",");
                    }
                    sb.AppendFormat(CultureInfo.InvariantCulture,
                                    "\"{0}\":\"{1}\"",
                                    keyValue.Key, JsonWriter.QuoteJScriptString(keyValue.Value));
                    firstItem = false;
                }
            }
            else {
                foreach (int key in _changedKeys.Keys) {
                    if (firstItem == false) {
                        sb.Append(",");
                    }
                    sb.AppendFormat(CultureInfo.InvariantCulture,
                                    "\"{0}\":\"{1}\"",
                                    key, JsonWriter.QuoteJScriptString(_data[key]));
                    firstItem = false;
                }
            }

            sb.Append("}");

            return sb.ToString();
        }
    }
}
